package com.neo.tiny.admin.service.sys.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.neo.tiny.admin.entity.sys.SysUserPost;
import com.neo.tiny.admin.mapper.sys.SysUserPostMapper;
import com.neo.tiny.admin.mapper.sys.SysUserRoleMapper;
import com.neo.tiny.admin.params.sys.UserParams;
import com.neo.tiny.admin.service.sys.SysUserService;
import com.neo.tiny.admin.entity.sys.SysUser;
import com.neo.tiny.admin.entity.sys.SysUserRole;
import com.neo.tiny.admin.mapper.sys.SysUserMapper;
import com.neo.tiny.admin.vo.user.SysUserVO;
import com.neo.tiny.common.constant.CacheConstants;
import com.neo.tiny.common.constant.ErrorCodeConstants;
import com.neo.tiny.common.exception.WebApiException;
import com.neo.tiny.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Description:
 * @Author: yqz
 * @CreateDate: 2022/8/7 14:00
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();

    @Autowired
    private SysUserMapper userMapper;

    @Autowired
    private SysUserRoleMapper userRoleMapper;

    @Autowired
    private SysUserPostMapper userPostMapper;

    @Autowired
    private RedisService redisService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public IPage<SysUserVO> getUserWithRoleDeptPage(Page<SysUserVO> page, SysUserVO vo) {
        return userMapper.getUserVosPage(page, vo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveUser(UserParams params) {
        SysUser sysUser = new SysUser();
        BeanUtil.copyProperties(params, sysUser);

        sysUser.setPassword(ENCODER.encode(params.getPassword()));
        baseMapper.insert(sysUser);
        //保存用户与角色的关系
        Optional.ofNullable(params.getRole()).ifPresent(roles -> {
            roles.stream().map(roleId -> {
                SysUserRole userRole = new SysUserRole();
                userRole.setUserId(sysUser.getId());
                userRole.setRoleId(roleId);
                return userRole;
            }).forEach(userRoleMapper::insert);
        });
        // 保存用户与岗位的关系
        Optional.ofNullable(params.getPost()).ifPresent(posts -> {
            posts.stream().map(postId -> {
                SysUserPost userPost = new SysUserPost();
                userPost.setPostId(postId);
                userPost.setUserId(sysUser.getId());
                return userPost;
            }).forEach(userPostMapper::insert);
        });
        return Boolean.TRUE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean editUser(UserParams params) {
        // 清空缓存
        String key = CacheConstants.USER_DETAILS + StrUtil.COLON + params.getUserName();
        redisService.del(key);

        SysUser sysUser = new SysUser();
        BeanUtil.copyProperties(params, sysUser);
        if (StrUtil.isNotBlank(params.getPassword())) {
            sysUser.setPassword(ENCODER.encode(params.getPassword()));
        }
        // 更新用户
        updateById(sysUser);

        // 更新用户角色关系
        if (CollectionUtil.isNotEmpty(params.getRole())) {
            userRoleMapper.delete(new LambdaUpdateWrapper<SysUserRole>()
                    .eq(SysUserRole::getUserId, sysUser.getId()));
            params.getRole().stream().map(roleId -> {
                SysUserRole userRole = new SysUserRole();
                userRole.setRoleId(roleId);
                userRole.setUserId(sysUser.getId());
                return userRole;
            }).forEach(userRoleMapper::insert);
        } else {
            userRoleMapper.delete(new LambdaUpdateWrapper<SysUserRole>()
                    .eq(SysUserRole::getUserId, sysUser.getId()));
        }

        // 更新用户和岗位关系
        if (CollectionUtil.isNotEmpty(params.getPost())) {
            userPostMapper.delete(new LambdaUpdateWrapper<SysUserPost>()
                    .eq(SysUserPost::getUserId, sysUser.getId()));
            params.getPost().stream().map(postId -> {
                SysUserPost userPost = new SysUserPost();
                userPost.setUserId(sysUser.getId());
                userPost.setPostId(postId);
                return userPost;
            }).forEach(userPostMapper::insert);
        } else {
            userPostMapper.delete(new LambdaUpdateWrapper<SysUserPost>()
                    .eq(SysUserPost::getUserId, sysUser.getId()));
        }

        return Boolean.TRUE;
    }

    @Override
    public void validUsers(Set<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return;
        }
        // 获得用户信息

        List<SysUser> userList = userMapper.selectBatchIds(ids);
        Map<Long, SysUser> userMap = userList.stream()
                .collect(Collectors.toMap(SysUser::getId, Function.identity(), (key1, key2) -> key1));

        ids.forEach(userId -> {
            SysUser user = userMap.get(userId);
            if (Objects.isNull(user)) {
                throw new WebApiException(ErrorCodeConstants.USER_NOT_EXISTS);
            }
        });
    }

    /**
     * 后台重置用户密码
     *
     * @param userId      用户id
     * @param newPassword 新密码
     */
    @Override
    public void updateUserPassword(Long userId, String newPassword) {
        SysUser user = getById(userId);
        if (ObjectUtil.isEmpty(user)) {
            throw new WebApiException(ErrorCodeConstants.USER_NOT_EXISTS);
        }
        user.setPassword(passwordEncoder.encode(newPassword));
        updateById(user);
        // 退出登录后，清除用户信息缓存
        String username = user.getUserName();
        String key = CacheConstants.USER_DETAILS + StrUtil.COLON + username;
        redisService.del(key);
    }

}
